import logging
import re
import traceback

from handlers.connection import connection
from utils.enums import RegisterEnum, CommandEnum, CollectEnum
from utils.errors import DeviceNotConnectError
from utils.handler_tools import msg_tool


logger = logging.getLogger(__name__)
ip_rex = re.compile(r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}')


class Register:
    """
    寄存器类
    """

    _instance = None

    def __new__(cls, *args, **kwargs):
        if not cls._instance:
            cls._instance = object.__new__(cls)
        return cls._instance

    @property
    def measurement(self):
        return [1, 2, 3, 4]
    
    @property
    def hz_list(self):
        return [2000, 1000, 800, 600, 500, 400, 300, 200, 100, 80, 60, 50, 40, 30, 20, 10, 8, 6, 5, 4, 3, 2, 1]

    def start(self, *, cat, command, data):
        func = f'_{cat}_{command}'
        try:
            sn = data['sn']
            self._check(sn)
            return getattr(self, func)(sn, data)
        except DeviceNotConnectError as e:
            logger.warning(e.message)
            return False, e.message
        except AttributeError:
            logger.error(f'{func} not found, return')
            return False, 'function not found'
        except Exception:
            logger.error(f'register process error, msg: {traceback.format_exc()}')
            return False, 'fail'

    def get_device_info(self, *, sn, attr):
        try:
            self._check(sn)
            handler = connection.get_alive_handler(sn=sn)
            return True, 'success', getattr(handler, attr)
        except DeviceNotConnectError as e:
            logger.warning(e.message)
            return False, e.message, None
        except AttributeError:
            return False, f'attribute: {attr} not found', None

    @staticmethod
    def get_devices():
        return [{
            'ip': v['handler'].ip,
            'sn': k,
            'mm': v['handler'].m,
            'hz': v['handler'].hz
        } for k, v in connection.alive_handler_dict.items()]

    @staticmethod
    def _check(sn):
        if sn not in connection.alive_handler_dict.keys():
            raise DeviceNotConnectError(message=f'设备: {sn} 未连接')

    @staticmethod
    def _control_collect(sn, data):
        try:
            cmd = int(data['signal'])
            if cmd not in CollectEnum.valid_enums():
                return False, f"指令: {cmd}不在有效范围, 请重试"
        except Exception:
            logger.error(f"process collect config error, msg: {traceback.format_exc()}")
            return False, '发生异常'
        else:
            handler = connection.get_alive_handler(sn=sn)
            msg = [CollectEnum.get_operation_msg(cmd)]
            msg = msg_tool.generate(command=CommandEnum.WRITE, token=handler.token, content=msg)
            msg_tool.send(handler, bytes(msg))
            connection.alive_handler_dict[sn]['collect'] = cmd
            return True, f'采集设置: {cmd} 已写入: {handler.sn}'

    @staticmethod
    def _config_ip(sn, data):
        if not connection.allowed:
            return False, '当前没有连接设备, 请在连接后重试'

        ip1 = data['origin']
        ip2 = data['dest']
        ips = ip_rex.findall(f'{ip1}, {ip2}')
        if not ips or len(ips) != 2:
            return False, 'IP格式有误'

        ips, ip2 = ip1.split('.'), ip2.split('.')
        ips.extend(ip2)
        ips = list(map(int, ips))

        handler = connection.allowed[0]
        ips.insert(0, RegisterEnum.SELF)
        msg = msg_tool.generate(command=CommandEnum.WRITE, token=handler.token, content=ips)
        msg_tool.send(handler, bytes(msg))
        handler.ip = ip2
        return True, f'IP配置: {data["dest"]} 已写入 {handler.sn}'

    @staticmethod
    def _config_sn(old, data):
        new = data['dest']
        value = connection.alive_handler_dict.pop(old)
        connection.alive_handler_dict[new] = value
        handler = connection.get_alive_handler(sn=new)
        new = [i for i in (new + r'\0').encode()]
        content = [RegisterEnum.SN]
        content.extend(new)
        msg = msg_tool.generate(command=CommandEnum.WRITE, token=handler.token, content=content)
        msg_tool.send(handler, bytes(msg))
        msg = f'设备: {old} SN号已重新设置为: {data["dest"]}'
        handler.sn = new
        return True, msg

    def _config_measurement(self, sn, data):
        """
        量程
        :return:
        """
        try:
            m = int(data['m'])
            if m not in self.measurement:
                return False, f'量程: {m} 不在有效范围内, 请重新设置'
            handler = connection.get_alive_handler(sn=sn)
            content = [RegisterEnum.MEASUREMENT, m]
            msg = msg_tool.generate(command=CommandEnum.WRITE, token=handler.token, content=content)
            msg_tool.send(handler, bytes(msg))
            handler.m = m
            return True, f'量程选项: {m} 已写至设备: {sn}'
        except ValueError:
            return False, '请输入正确的量程类型'
        except Exception:
            logger.error(f'config m error, msg: {traceback.format_exc()}')
            return False, 'fail'

    def _config_hz(self, sn, data):
        """
        传感器频率
        :return:
        """
        try:
            hz = int(data['hz'])
            if hz not in self.hz_list:
                return False, f'频率: {hz} 不在有效范围内，请重新设置设置'
            handler = connection.get_alive_handler(sn=sn)
            content = [RegisterEnum.HZ]
            content.extend(msg_tool.one2two_byte(hz))
            msg = msg_tool.generate(command=CommandEnum.WRITE, token=handler.token, content=content)
            msg_tool.send(handler, bytes(msg))
            handler.hz = hz
            return True, f'频率：{hz} 已写至设备: {sn}'
        except Exception:
            logger.error(f'config hz error, msg: {traceback.format_exc()}')
            return False, 'fail'

    def _config_decoupling(self, sn, data):
        """
        解耦系数
        :param sn:
        :param data:
        :return:
        """
        try:
            de = data['de']
            handler = connection.get_alive_handler(sn=sn)
            handler.de = de
            content = [RegisterEnum.DECOUPLING]
            des = [i for i in de.encode()]
            content.extend(des)
            msg = msg_tool.generate(command=CommandEnum.WRITE, token=handler.token, content=content)
            msg_tool.send(handler, bytes(msg))
            handler.de = de
            return True, f'解耦系数：{de} 已写至设备: {sn}'
        except Exception:
            logger.error(f'config de error, msg: {traceback.format_exc()}')
            return False, 'fail'


register = Register()
